using System.Collections.Generic;
using Godot;

namespace Arcane.Source.TileMatch.Tile;

public abstract class GravityTile : IDynTile
{
    public interface IPhase;

    public class Idle : IPhase;
    public class Droping : IPhase
    {
        public int tick;
    }

    private IPhase _phase;

    public GravityTile(IPhase initialPhase)
    {
        _phase = initialPhase;
    }

    public GravityTile() : this(new Droping { tick = 0 })
    {

    }

    public abstract bool Interactable();
    public abstract bool Matches(ITile other);
    public abstract bool Swapable(ITile tile);

    public virtual void OnMatch(Match match, TilePos pos, List<TilePos> matchedPos) { }

    public virtual bool Tick(Match match, TilePos pos)
    {
        if (_phase is Droping droping)
        {
            if (droping.tick < Rule.DROP_TICK)
            {
                droping.tick = Mathf.Clamp(droping.tick + 1, 0, Rule.DROP_TICK);
                match.MarkDirty(pos);
            }
            else
            {
                if (match.TryMove(pos, pos.Bottom()))
                {
                    droping.tick = 0;
                    match.MarkDirty(pos.Bottom());
                }
                else
                {
                    _phase = new Idle();
                    match.QueueMatch(pos);
                }
            }
            return true;
        }
        return false;
    }

    public virtual void OnNeighborRemove(Match match, TilePos pos, TileSide side)
    {
        if (_phase is Idle && side == TileSide.Bottom)
        {
            _phase = new Droping { tick = 0 };
            match.TryMove(pos, pos.Bottom());
            match.MarkDirty(pos.Bottom());
        }
    }

    public bool IsDroping() => _phase is Droping;
    public bool IsDroping(out int tick)
    {
        if (_phase is Droping drop)
        {
            tick = drop.tick;
            return true;
        }
        tick = 0;
        return false;
    }
    public bool IsIdle() => _phase is Idle;
}